/**
 * 广寒宫
 * 网址:www.guanghangong.xyz
 */
package org.moon.framework.autoconfigure.secure.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.moon.framework.autoconfigure.MoonConstants;
import org.moon.framework.autoconfigure.cache.CacheService;
import org.moon.framework.autoconfigure.config.SpringContextConfig;
import org.moon.framework.autoconfigure.exception.domain.MoonException;
import org.moon.framework.autoconfigure.secure.AuthUtils;
import org.moon.framework.autoconfigure.secure.annotation.Idempotent;
import org.moon.framework.autoconfigure.utils.ClassUtils;
import org.moon.framework.autoconfigure.utils.Func;
import org.moon.framework.autoconfigure.utils.SecurityUtils;

import java.lang.reflect.Method;

/**
 * 解决表单重复提交 幂等操作
 * @author moon
 */
@Aspect
@Slf4j
public class IdempotentAspect {
	
	/**
	 * 切 方法 和 类上的 @FormRepeat 注解
	 */
	@Around(
		"@annotation(org.moon.framework.autoconfigure.secure.annotation.Idempotent) || " +
			"@within(org.moon.framework.autoconfigure.secure.annotation.Idempotent)"
	)
	public Object idempotent(ProceedingJoinPoint point) throws Throwable {
		MethodSignature ms = (MethodSignature) point.getSignature();
		Method method = ms.getMethod();
		Idempotent idempotent = ClassUtils.getAnnotation(method, Idempotent.class);
		if(idempotent==null)return true;
		CacheService cacheService = SpringContextConfig.getBean(CacheService.class);
		//要保证同一个人的唯一性,md5是为了避免key过长
		String key = SecurityUtils.md5(AuthUtils.getCurrentUserId()+":"+ Func.getRequest().getRequestURI());
		String v = cacheService.get(key);
        if(v!=null){
			String msg = Func.isBlank(idempotent.message())?MoonConstants.IDEMPOTENT.getMsg():idempotent.message();
			throw new MoonException(MoonConstants.IDEMPOTENT.getCode(),msg);
		}
		cacheService.set(key, "idempotent",idempotent.timeout());
		try{
        	return point.proceed();
        }finally{
			cacheService.del(key);
        }
	}
}